/*******************************************************************************
 * Package: com.song.sharding.web
 * Type:    IdempotentWeb
 * Date:    2024-01-06 15:08
 *
 * Copyright (c) 2024 LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.kkxxpoi.controller;

import com.song.common.idempotent.IdempotentService;
import com.song.common.idworker.Sid;
import com.song.common.util.CommUtil;
import com.song.common.util.RedisServiceUtil;
import com.song.common.annotation.ResponseInfoSkin;
import com.song.kkxxpoi.entity.IntEndScaleForecastEntity;
import com.song.kkxxpoi.mapper.IIntEndScaleForecastMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * 功能描述：接口幂等性
 *
 * @author Songxianyang
 * @date 2024-01-06 15:08
 */
@Slf4j
@Api(tags = "接口幂等性")
@RestController
@RequestMapping("/idempotent-web")
@ResponseInfoSkin
public class IdempotentWeb {

    @Resource
    private IIntEndScaleForecastMapper iIntEndScaleForecastMapper;
    @Resource
    private Sid sid;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private RedisServiceUtil redisServiceUtil;
    @Resource
    private IdempotentService idempotentService;

    public static final String TOKEN = "html:";

    /**
     * 查询列表结构体种必须包含revision字段 做修改得时候记得给回传过来
     *
     * @param name
     * @param revision
     */
    @SneakyThrows
    @GetMapping("/update")
    @ApiOperation("修改幂等-乐观锁")
    public void update(@RequestParam String name, @RequestParam Integer revision) {
        log.info(">>>>>>>修改幂等<<<<<<<<");
        TimeUnit.SECONDS.sleep(5);
        IntEndScaleForecastEntity entity = new IntEndScaleForecastEntity();
        entity.setId("240106FN68MKPZC0");
        entity.setSubProjectName(name);
        entity.setRevision(revision);
        iIntEndScaleForecastMapper.update(entity);
    }


    /**
     * 采用分布式锁来实现 幂等性
     * 首先我们需要采用token机制
     * 再点击编辑或者新增页面得时候生成一个uuid 并且存入redis当中
     * 通多redisson 分布式锁机制来实现
     *
     * @param htmlId 前端生成的id（/html-id这个接口生成出来的id）
     */
    @SneakyThrows
    @GetMapping("/insert")
    @ApiOperation("新增幂等-分布式锁")
    public String insert(@RequestParam String htmlId) {
        log.info(">>>>>>>新增幂等<<<<<<<<");
        TimeUnit.SECONDS.sleep(5);


        RLock lock = redissonClient.getLock(htmlId);
        lock.lock(30, TimeUnit.SECONDS);
        try {
            String redis = redisServiceUtil.get(TOKEN + htmlId);
            if (CommUtil.isEmpty(redis)) {
                return "请输入正确的token";
            }
            IntEndScaleForecastEntity entity = new IntEndScaleForecastEntity();
            String id = sid.nextShort();
            entity.setId(id);
            entity.setSubProjectCode(htmlId);
            entity.setSubProjectName("我的project项目" + id);
            iIntEndScaleForecastMapper.insert(entity);
            // 执行业务代码
            redisServiceUtil.del(TOKEN + htmlId);
            return "插入成功！";


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁锁拉拉" + Thread.currentThread().getName());
            lock.unlock();
        }
        return "s";


    }




    @SneakyThrows
    @GetMapping("/insert-renewal")
    @ApiOperation("锁续期操作")
    public String insertRenewal(@RequestParam String htmlId) {
        log.info(">>>>>>>新增幂等<<<<<<<<");
        TimeUnit.SECONDS.sleep(5);


        RLock lock = redissonClient.getLock(htmlId);
        try {
            lock.lock();
            // 执行业务操作
            Thread.sleep(60000);
            System.out.println("执行业务操作-success");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("解锁锁拉拉" + Thread.currentThread().getName());
            lock.unlock();
        }
        return "s";


    }



    @GetMapping("/html-id")
    @ApiOperation("进入新增或者编辑页面的时候调用一下生成id的方法")
    public String htmlId() {
        String id = sid.nextShort();
        // redisServiceUtil.set(TOKEN + id, id);
        return id;
    }

    /**
     *
     * @param idempotentKey 唯一的id
     * @return
     */
    @GetMapping("/submit")
    public ResponseEntity<?> submitSurvey(@RequestHeader("X-Idempotent-Key") String idempotentKey) throws InterruptedException {

        // 幂等检查（5分钟过期）
        // 0标识存在  1标识不存在
        // return result != null && result == 1;
        //存在 0==1 false的非 就是true
        // 不存在 1==1 true 取非  就是false
        if (!idempotentService.checkRequest(idempotentKey, 300)) {
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body("重复提交请求");
        }


        // 业务处理（示例）
        try {
            // 实际业务逻辑（数据库操作等）
            System.out.println("实际业务逻辑（数据库操作等）：" + idempotentKey);
            // 模拟处理耗时
            Thread.sleep(100);
            return ResponseEntity.ok("提交成功");
        } catch (Exception e) {
            // 业务异常时删除幂等标记（可选）
            redisServiceUtil.del(idempotentKey);
            throw e;
        }
    }
}
